package solver.moves;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import model.IncrementalValidator;
import model.Solution;
import model.SolverEnvironment;
import model.Service;
/**
 * The Move tries to make an exchange between processes of the same
 * service. It returns the first pair that 
 * @author alefrag
 *
 */
public class ServiceCostReducer extends AbstractComplexMove {
	
	List<Integer> s_id;

	public ServiceCostReducer(SolverEnvironment env) {
		super(env);
	}
	
	@Override
	public void init() {
		super.init();
		s_id = new ArrayList<Integer>();
		for(int s=0; s<getProblem().S;s++){
			Service aService = getProblem().getServices().get(s);
			if(aService.getProcesses().size()>=2)
				s_id.add(s);
		}
//		System.out.println("Services >=2 procs:"+s_id);
	}

	@Override
	public boolean performMove() {
		boolean flag = false;
//		long[] memory=null;
//		int starts = random.nextInt(problem.S);
		if(s_id.size()==0)
			return false;
		int s = s_id.get(getRandom().nextInt(s_id.size()));
		Solution pot_sol = env.getPotentialSolution();
//services:for(int _s=starts; _s<problem.S+starts;_s++){
//			int s = _s%problem.S;
//		    int s = starts;
			Service aService = getProblem().getServices().get(s);
//			if(aService.getProcesses().size()<=1)
////				continue;
//				return flag;
		long init_cost = getCc().getNewSolutionCost();
			for (int p=0; p<aService.getProcesses().size();p++){
				int pId = aService.getProcesses().get(p);
				long local_cost = getCc().getNewSolutionCost();
				for(int op=p+1; op<aService.getProcesses().size();op++){
					int pId2 = aService.getProcesses().get(op);
					int orig_m_id1 = pot_sol.getMachineIdForProcessId(pId);
					int orig_m_id2 = pot_sol.getMachineIdForProcessId(pId2);				
					if (isFeasible(pId,orig_m_id1, pId2,orig_m_id2)){
//						assert(env.getValidator().isProcessExchangeFeasibleNoSchedule(pId,orig_m_id1, pId2,orig_m_id2)==true);
						long newcost=env.getCostCalculator().getNewSolutionCost()+
//						long delta = 
								env.getCostCalculator().getProcessExcahngeProfit(pot_sol, pId, pId2, 
										orig_m_id1,orig_m_id2);
						if(newcost<=local_cost){
//						if(delta<=0){
							makeExchange(pId,orig_m_id1, pId2,orig_m_id2);
//							invoker.clearCommands();
//							memory = cc.saveAndGetCostComponentMemory();
							getCc().updateNewSolutionCost();
//							System.out.println("Success in DCR Move.s="+s+
//									" orig_cost="+init_cost+" new_cost="+newcost+
//									" gain="+(init_cost-newcost));
							flag=true;
//							break;
						}
					}
				}
			}
//		}
		
//		getCc().updateNewSolutionCost();
//		//TODO: This is a quick and dirty fix
//		if(flag)
//			getCc().computeCost();
		getCc().clearDelta();
		return flag;
	}
	
	boolean isFeasible(int p_id1,int orig_m_id1, int p_id2, int orig_m_id2){
		IncrementalValidator iv = env.getValidator();
		if(!iv.isMachineCapacityFeasible(p_id2, p_id1, orig_m_id2))
			return false;
		if (!iv.isMachineCapacityFeasible(p_id1, p_id2, orig_m_id1))
			return false;
		if (!iv.isFeasibleForTransientConstraintsSuperFastNoSchedule(p_id1, orig_m_id1, p_id2,
				orig_m_id2))
			return false;
		return true;
	}

}
